<!--
绘制流程图界面
-->

<template>
  <div class="container">
    <!-- 创建一个canvas画布 npmn-js是通过canvas实现绘图的，并设置ref让vue获取到element -->
    <div class="bpmn-container">
      <div class="bpmn-canvas" ref="canvas"></div>
      <!-- 工具栏显示的地方 -->
      <div class="bpmn-js-properties-panel" id="js-properties-panel"></div>
      <bpmn-panel v-if="bpmnModeler" :modeler="bpmnModeler" />
      <!-- 把操作按钮写在这里面 -->
      <div class="action-foot" v-if="!onlyView">
        <input hidden ref="file" type="file" @change="showRealPath"/>
        <a hidden ref="downloadLink"></a>
        <ButtonGroup>
          <Button icon="md-cloud-upload" @click="openBpmn"></Button>
          <Button class="new" icon="md-refresh" title="重置" @click="newDiagram"></Button>
          <Button class="new" icon="ios-undo" title="撤销" @click="undo"></Button>
          <Button class="new" icon="ios-redo" title="复原" @click="redo"></Button>
          <Button icon="md-arrow-down" title="下载bpmn" @click="downloadBpmn"></Button>
          <Button icon="md-image" title="下载svg" @click="downloadSvg"></Button>
          <Button icon="md-done-all" title="部署" @click="deploy"></Button>
        </ButtonGroup>
      </div>
    </div>

  </div>
</template>

<script>
import BpmnModeler from "bpmn-js/lib/Modeler";
// 工具栏相关
import propertiesProviderModule from "bpmn-js-properties-panel/lib/provider/camunda";
import propertiesPanelModule from "bpmn-js-properties-panel";
import camundaModdleDescriptor from "camunda-bpmn-moddle/resources/camunda";
//部分自定义工具栏工具
import customPalette from '@/api/customcontrols'
//部分自定义工具栏工具
import bpmnPanel from '@/view/activiti/coustom/bpmn-panel'

// 汉化
import customTranslate from "@/api/bpmn/customTranslate";
//初始化bpmn模板
import bpmnTemplateXml from "@/api/bpmn/bpmndefault";
//xml转json工具
import x2js from 'x2js'

import * as API from "@/api/bpmn-api";


export default {
  name:"activiti-setting",
  components:{
    bpmnPanel
  },
  props:{
    currentProcess:{
      type:Object,
      default:{
      }
    }
  },
  data() {
    return {
      bpmnModeler: null,
      canvas: null,
      xmlUtil: null,
      onlyView: false,
    };
  },
  methods: {
    newDiagram() {
      this.createNewDiagram(bpmnTemplateXml);
    },
    //下载bpmn格式的流程图
    downloadBpmn() {
      this.bpmnModeler.saveXML({format: true}, (err, xml) => {
        if (!err) {
          // 获取文件名
          const name = this.xmlUtil.xml2js(xml).definitions.process._id + `.bpmn`;
          // 将文件名以及数据交给下载方法
          this.download({name: name, data: xml});
        }
      });
    },

    //撤销上一步
    undo() {
      this.bpmnModeler.get('commandStack').undo()
    },

    //前进下一步
    redo() {
      this.bpmnModeler.get('commandStack').redo()
    },

    //获取文件
    showRealPath() {
      const selectedFile = this.$refs.file.files[0]
      // 后缀获取
      let suffix = ''
      try {
        const fileArr = selectedFile.name.split('.')
        suffix = fileArr[fileArr.length - 1]
      } catch (err) {
        suffix = ''
      }
      if (suffix === '' || (suffix !== 'xml' && suffix !== 'bpmn')) {
        this.$Message.warning("不是有效的bpmn文件！")
        return
      }
      // FileReader对象，h5提供的异步api，可以读取文件中的数据。
      const reader = new FileReader()
      // readAsText是个异步操作，只有等到onload时才能显示数据。
      reader.readAsText(selectedFile)
      const that = this
      reader.onload = function () {
        // 当读取完成后回调这个函数,然后此时文件的内容存储到了result中,直接操作即可
        that.createNewDiagram(this.result)
      }
      // 防止选择同一个文件不执行此方法
      this.$refs.file.value = null
    },


    //下载svg格式的流程图
    downloadSvg() {
      this.bpmnModeler.saveXML({format: true}, (err, xml) => {
        if (!err) {
          // 获取文件名
          const name = this.xmlUtil.xml2js(xml).definitions.process._id + `.svg`;

          // 从建模器画布中提取svg图形标签
          let context = "";
          const djsGroupAll = this.$refs.canvas.querySelectorAll(".djs-group");
          for (let item of djsGroupAll) {
            context += item.innerHTML;
          }
          // 获取svg的基本数据，长宽高
          const viewport = this.$refs.canvas
            .querySelector(".viewport")
            .getBBox();
          // 将标签和数据拼接成一个完整正常的svg图形
          const svg = `
            <svg
              xmlns="http://www.w3.org/2000/svg"
              xmlns:xlink="http://www.w3.org/1999/xlink"
              width="${viewport.width}"
              height="${viewport.height}"
              viewBox="${viewport.x} ${viewport.y} ${viewport.width} ${viewport.height}"
              version="1.1"
              >
              ${context}
            </svg>
          `;
          // 将文件名以及数据交给下载方法
          this.download({name: name, data: svg});
        }
      });
    },

    //部署流程
    deploy() {
      this.bpmnModeler.saveXML({format: true}, (err, xml) => {
        if (!err) {
          // 获取文件名
          const params = {
            resourceName: this.xmlUtil.xml2js(xml).definitions.process._id + `.bpmn`,
            name: this.xmlUtil.xml2js(xml).definitions.process._name,
            bpmnStr: xml
          }
          if (!params.name){
            this.$Message.warning("请填写流程名称！")
            return;
          }
          API.addDeploymentByString(params).then(res => {
            if (res.code === "0") {
              this.$Message.success("部署成功！")
              this.$emit("deploy-back")
            } else {
              this.$Message.error("部署失败！")
            }
          })
        }
      });
    },

    //读取bpmn文件
    openBpmn() {
      this.$refs.file.dispatchEvent(new MouseEvent('click'))
    },

    //下载事件
    download({name = "diagram.bpmn", data}) {
      // 这里就获取到了之前设置的隐藏链接
      const downloadLink = this.$refs.downloadLink;
      // 把数据转换为URI，下载要用到的
      const encodedData = encodeURIComponent(data);
      if (data) {
        // 将数据给到链接
        downloadLink.href =
          "data:application/bpmn20-xml;charset=UTF-8," + encodedData;
        // 设置文件名
        downloadLink.download = name;
        // 触发点击事件开始下载
        downloadLink.click();
      }
    },

    //初始化构图
    async init() {
      // 获取画布 element
      this.canvas = this.$refs.canvas;

      // 将汉化包装成一个模块
      const customTranslateModule = {
        translate: ["value", customTranslate]
      };

      // 创建Bpmn对象
      this.bpmnModeler = new BpmnModeler({
        // 设置bpmn的绘图容器为上门获取的画布 element
        container: this.canvas,

        // 加入工具栏支持
        propertiesPanel: {
          parent: "#js-properties-panel"
        },
        additionalModules: [
          // 工具栏模块
          propertiesProviderModule,
          propertiesPanelModule,
          //添加自定义工具
          customPalette,
          // 汉化模块
          customTranslateModule
        ],
        moddleExtensions: {
          camunda: camundaModdleDescriptor
        }
      });

      //如果不是需要回显的数据，则执行下面的语句构建一个初始的图
      if (this.currentProcess.deploymentId && this.currentProcess.resourceName) {
        this.onlyView = this.currentProcess.isView
        this.viewBpmn()
      } else {
        await this.createNewDiagram(bpmnTemplateXml);
      }
    },

    //根据xml内容构建模型图
    async createNewDiagram(bpmn) {
      // 将字符串转换成图显示出来;
      try {
        await this.bpmnModeler.importXML(bpmn);
      } catch (err) {
        this.$Message.error("打开模型出错,请确认该模型符合Bpmn2.0规范");
      }
    },

    //获取流程图xml
    viewBpmn() {
      API.getDefinitionXml({
        deploymentId: this.currentProcess.deploymentId,
        resourceName: this.currentProcess.resourceName
      }).then(res => {
        if (res.code === "0") {
          this.createNewDiagram(res.data)
        } else {
          this.$Message.error("查看流程图失败！")
        }
      })
    },
  },
  mounted() {
    this.init();
    this.xmlUtil = new x2js();
  }
};
</script>

<style>
/*左边工具栏以及编辑节点的样式*/
@import '~bpmn-js/dist/assets/diagram-js.css';
@import '~bpmn-js/dist/assets/bpmn-font/css/bpmn.css';
@import '~bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css';
@import '~bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css';
</style>

<style lang="less" scoped>
.container {
  width: 100%;
  height: 100%;

  /deep/ .bjs-powered-by {
    display: none;
  }
  /deep/ .bpmn-js-properties-panel{
    display: none;
  }
  .bpmn-container {
    width: 100%;
    height: 100%;
    display: flex;

    .bpmn-canvas {
      width: 100%;;
      height: 100%;
    }

    .bpmn-js-properties-panel {
      height: inherit;
      overflow-y: auto;
    }

    .action-foot{
      position: fixed;
      right: 100px;
      bottom: 40px;
      width: 100%;
      height: 50px;
      text-align: center;
    }
  }

  .action {
    position: fixed;
    bottom: 10px;
    display: flex;

    Button {
      margin-left: 5px;
    }

    /deep/ .ivu-upload-list {
      margin-top: 0px !important;
    }
  }
}
</style>
